/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.datalayer.daoimpl;

import cz.muni.fi.diplomka.datalayer.dao.CityArmyDao;
import cz.muni.fi.diplomka.datalayer.entity.CityArmyEntity;
import cz.fi.muni.diplomka.common.Squad;
import cz.fi.muni.diplomka.common.Unit;
import cz.fi.muni.diplomka.common.enumeration.UnitType;
import cz.muni.fi.diplomka.datalayer.util.DbConnector;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Jakub Kutil
 */
public class CityArmyDaoImpl implements CityArmyDao {

    private Connection con = null;
    private PreparedStatement ps = null;
    private ResultSet rs = null;

    public CityArmyDaoImpl() {
    }

    @Override
    public void addArmy(CityArmyEntity cityArmyEntity) {
        if (cityArmyEntity == null) {
            throw new IllegalArgumentException("ArmyEntity can not be null");
        }
        try {
            con = DbConnector.getDBConnection();
            String insert = "INSERT INTO city_army (owner_city_id, city_id, name, guard)"
                    + "VALUES (?,?,?,?)";
            ps = con.prepareStatement(insert);

            ps.setLong(1, cityArmyEntity.getOwnerCityId());
            ps.setLong(2, cityArmyEntity.getCityId());
            ps.setString(3, cityArmyEntity.getName());
            ps.setBoolean(4, cityArmyEntity.isGuard());

            ps.executeUpdate();

            rs = ps.getGeneratedKeys();
            rs.next();

            String getId = "SELECT max(id) FROM city_army";

            ps = con.prepareStatement(getId);
            rs = ps.executeQuery();
            rs.next();
            Long id = rs.getLong(1);

            insert = "INSERT INTO city_army_units (army_id, position, name, count, threshold)"
                    + "VALUES (?,?,?,?,?)";

            ps = con.prepareStatement(insert);

            for (Squad squad : cityArmyEntity.getArmy().getSquads()) {
                ps.setLong(1, id);
                ps.setInt(2, squad.getPosition());
                ps.setString(3, squad.getUnit().getName().toString());
                ps.setInt(4, (int) squad.getCount());
                ps.setInt(5, (int) squad.getThreshold());

                ps.executeUpdate();
            }

        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public void editArmy(CityArmyEntity cityArmyEntity) {
        if (cityArmyEntity == null) {
            throw new IllegalArgumentException("City Army Entity can not be null");
        }
        try {
            con = DbConnector.getDBConnection();
            String update = "UPDATE city_army SET owner_city_id=?, city_id=?, name=?, guard=? WHERE id=?";

            ps = con.prepareStatement(update);

            ps.setLong(1, cityArmyEntity.getOwnerCityId());
            ps.setLong(2, cityArmyEntity.getCityId());
            ps.setString(3, cityArmyEntity.getName());
            ps.setBoolean(4, cityArmyEntity.isGuard());
            ps.setLong(5, cityArmyEntity.getId());

            ps.executeUpdate();

            update = "UPDATE city_army_units SET name=?, count=?, threshold=? WHERE army_id=? AND position=?";

            ps = con.prepareStatement(update);

            for (Squad squad : cityArmyEntity.getArmy().getSquads()) {

                ps.setString(1, squad.getUnit().getName().toString());
                ps.setInt(2, (int) squad.getCount());
                ps.setInt(3, (int) squad.getThreshold());
                ps.setLong(4, cityArmyEntity.getId());
                ps.setInt(5, squad.getPosition());

                ps.executeUpdate();
            }

        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public void deleteArmy(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("ID can not be null");
        }
        try {
            con = DbConnector.getDBConnection();
            String delete = "DELETE FROM city_army_units WHERE army_id=?";

            ps = con.prepareStatement(delete);

            ps.setLong(1, id);

            ps.executeUpdate();

            delete = "DELETE FROM city_army WHERE id=?";

            ps = con.prepareStatement(delete);

            ps.setLong(1, id);

            ps.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
    }

    @Override
    public List<CityArmyEntity> getArmiesInCity(Long cityId) {
        if (cityId == null) {
            throw new IllegalArgumentException("City ID can not be null");
        }
        List<CityArmyEntity> cityArmyEntityList = new ArrayList<>();


        try {
            con = DbConnector.getDBConnection();
            String getArmiesInCity = "SELECT id, owner_city_id, city_id, city_army.name AS army_name, guard, position, city_army_units.name AS unit_name, count, threshold FROM city_army INNER JOIN city_army_units ON city_army.id = city_army_units.army_id WHERE city_id=?";

            ps = con.prepareStatement(getArmiesInCity);
            ps.setLong(1, cityId);

            rs = ps.executeQuery();
            Map<Integer, CityArmyEntity> armyMap = new HashMap();
            while (rs.next()) {
                if (!armyMap.containsKey(rs.getInt(1))) {
                    CityArmyEntity cityArmyEntity = new CityArmyEntity();

                    cityArmyEntity.setId(rs.getLong("id"));
                    cityArmyEntity.setOwnerCityId(rs.getLong("owner_city_id"));
                    cityArmyEntity.setCityId(rs.getLong("city_id"));
                    cityArmyEntity.setName(rs.getString("army_name"));
                    cityArmyEntity.setGuard(rs.getBoolean("guard"));

                    armyMap.put(rs.getInt("id"), cityArmyEntity);
                }

                Unit unitEntity = new Unit();
                unitEntity.setName(UnitType.valueOf(rs.getString("unit_name")));

                Squad squad = new Squad();
                squad.setPosition(rs.getInt("position"));
                squad.setUnit(unitEntity);
                squad.setCount(rs.getInt("count"));
                squad.setThreshold(rs.getInt("threshold"));

                armyMap.get(rs.getInt(1)).getArmy().getSquads().add(squad);
            }

            for (CityArmyEntity cityArmyEntity : armyMap.values()) {
                cityArmyEntityList.add(cityArmyEntity);
            }
        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
        return cityArmyEntityList;
    }

    @Override
    public List<CityArmyEntity> getAwayArmiesFromCity(Long cityId) {
        if (cityId == null) {
            throw new IllegalArgumentException("City ID can not be null");
        }
        List<CityArmyEntity> cityArmyEntityList = new ArrayList<>();


        try {
            con = DbConnector.getDBConnection();
            String getArmiesInCity = "SELECT id, owner_city_id, city_id, city_army.name AS army_name, guard, position, city_army_units.name AS unit_name, count, threshold FROM city_army INNER JOIN city_army_units ON city_army.id = city_army_units.army_id WHERE owner_city_id=? AND city_id <> ? ";

            ps = con.prepareStatement(getArmiesInCity);
            ps.setLong(1, cityId);
            ps.setLong(2, cityId);

            rs = ps.executeQuery();
            Map<Integer, CityArmyEntity> armyMap = new HashMap();
            while (rs.next()) {
                if (!armyMap.containsKey(rs.getInt(1))) {
                    CityArmyEntity cityArmyEntity = new CityArmyEntity();

                    cityArmyEntity.setId(rs.getLong("id"));
                    cityArmyEntity.setOwnerCityId(rs.getLong("owner_city_id"));
                    cityArmyEntity.setCityId(rs.getLong("city_id"));
                    cityArmyEntity.setName(rs.getString("army_name"));
                    cityArmyEntity.setGuard(rs.getBoolean("guard"));

                    armyMap.put(rs.getInt("id"), cityArmyEntity);
                }

                Unit unitEntity = new Unit();
                unitEntity.setName(UnitType.valueOf(rs.getString("unit_name")));

                Squad squad = new Squad();
                squad.setPosition(rs.getInt("position"));
                squad.setUnit(unitEntity);
                squad.setCount(rs.getInt("count"));
                squad.setThreshold(rs.getInt("threshold"));

                armyMap.get(rs.getInt(1)).getArmy().getSquads().add(squad);
            }

            for (CityArmyEntity cityArmyEntity : armyMap.values()) {
                cityArmyEntityList.add(cityArmyEntity);
            }
        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
        return cityArmyEntityList;
    }
    
    @Override
    public CityArmyEntity getArmyOnWallsInCity(Long cityId) {
        if (cityId == null) {
            throw new IllegalArgumentException("City ID can not be null");
        }
        Map<Integer, CityArmyEntity> armyMap = new HashMap();
        int id = 0;
        try {
            con = DbConnector.getDBConnection();
            String getArmiesInCity = "SELECT id, owner_city_id, city_id, city_army.name, guard, position, city_army_units.name AS unit_name, count, threshold FROM city_army INNER JOIN city_army_units ON city_army.id = city_army_units.army_id WHERE city_id=? AND guard=true";

            ps = con.prepareStatement(getArmiesInCity);
            ps.setLong(1, cityId);

            rs = ps.executeQuery();

            while (rs.next()) {
                if (!armyMap.containsKey(rs.getInt(1))) {

                    CityArmyEntity cityArmyEntity = new CityArmyEntity();
                    cityArmyEntity.setId(rs.getLong("id"));
                    cityArmyEntity.setOwnerCityId(rs.getLong("owner_city_id"));
                    cityArmyEntity.setCityId(rs.getLong("city_id"));
                    cityArmyEntity.setName(rs.getString("army.name"));
                    cityArmyEntity.setGuard(rs.getBoolean("guard"));

                    armyMap.put(rs.getInt("id"), cityArmyEntity);
                    id = rs.getInt(1);
                }

                Unit unitEntity = new Unit();
                unitEntity.setName(UnitType.valueOf(rs.getString("unit_name")));

                Squad squad = new Squad();
                squad.setPosition(rs.getInt("position"));
                squad.setUnit(unitEntity);
                squad.setCount(rs.getInt("count"));
                squad.setThreshold(rs.getInt("threshold"));

                armyMap.get(rs.getInt(1)).getArmy().getSquads().add(squad);
            }

        } catch (SQLException ex) {
            Logger.getLogger(CityArmyDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            DbConnector.closeConnection(rs, ps, con);
        }
        return armyMap.get(id);
    }
}
